﻿using SharpDX;
using SharpDX.DirectSound;
using SharpDX.Multimedia;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Windows.Interop;
using FragLabs.Audio.Codecs;

namespace PeerComLink
{
    class AudioPlaybackController
    {
        AutoResetEvent _autoResetEvent;
        DirectSound _device;
        SecondarySoundBuffer _secondaryBuffer;
        SecondarySoundBuffer _secondaryBuffer2;
        int _bufferSize;
        OpusDecoder _opusDec;

        NAudio.Wave.BufferedWaveProvider _playBuffer ;

        NAudio.Wave.DirectSoundOut _waveOut;

        //NAudio.Wave.WaveFileWriter _writer;

        [DllImport("user32.dll", SetLastError = false)]
        static extern IntPtr GetDesktopWindow();

        public AudioPlaybackController()
        {
            _device = new DirectSound();

            IntPtr windowHandle = GetDesktopWindow();

            _device.SetCooperativeLevel(windowHandle, CooperativeLevel.Priority);

            WaveFormat waveFormat = WaveFormat.CreateCustomFormat(WaveFormatEncoding.Pcm,
                App.WaveFormatParams.SamplesPerSecond, App.WaveFormatParams.Channels,
                App.WaveFormatParams.AverageBytesPerSecond, App.WaveFormatParams.BlockAlign,
                App.WaveFormatParams.BitsPerSample);

            //NAudio.Wave.WaveFormat format = NAudio.Wave.WaveFormat.CreateCustomFormat(NAudio.Wave.WaveFormatEncoding.Pcm,
            //    App.WaveFormatParams.SamplesPerSecond, App.WaveFormatParams.Channels,
            //    App.WaveFormatParams.AverageBytesPerSecond, App.WaveFormatParams.BlockAlign,
            //    App.WaveFormatParams.BitsPerSample);
            //_writer = new NAudio.Wave.WaveFileWriter("out.wav", format);

            SoundBufferDescription playbackBufferDescription = new SoundBufferDescription();
            playbackBufferDescription.Flags = BufferFlags.PrimaryBuffer;
            playbackBufferDescription.AlgorithmFor3D = Guid.Empty;

            PrimarySoundBuffer playbackBuffer = new PrimarySoundBuffer(_device, playbackBufferDescription);
            playbackBuffer.Play(0, PlayFlags.Looping);

            var secondaryBufferDesc = new SoundBufferDescription();
            _bufferSize = secondaryBufferDesc.BufferBytes = waveFormat.ConvertLatencyToByteSize(20) * 8;
            secondaryBufferDesc.Format = waveFormat;
            secondaryBufferDesc.Flags = BufferFlags.GlobalFocus | BufferFlags.GetCurrentPosition2 | BufferFlags.ControlVolume;
            secondaryBufferDesc.AlgorithmFor3D = Guid.Empty;

            _secondaryBuffer = new SecondarySoundBuffer(_device, secondaryBufferDesc);
            _secondaryBuffer2 = new SecondarySoundBuffer(_device, secondaryBufferDesc);
            _opusDec = OpusDecoder.Create(App.WaveFormatParams.SamplesPerSecond, App.WaveFormatParams.Channels);

            //_secondaryBuffer.Play(0, PlayFlags.Looping);

            _playBuffer = new NAudio.Wave.BufferedWaveProvider(new NAudio.Wave.WaveFormat(48000, 16, 1));
            //_playBuffer.BufferLength = waveFormat.ConvertLatencyToByteSize(20) * 8;
            _playBuffer.DiscardOnBufferOverflow = true;
            _waveOut = new NAudio.Wave.DirectSoundOut();
            _waveOut.Init(_playBuffer);

            _waveOut.Play();
        }

        int bufferSel = 0;

        internal void WriteData(byte[] data)
        {
            int decodedLength;
            byte[] decodedData = _opusDec.Decode(data, data.Length, out decodedLength);

            byte[] decodedData2 = new byte[decodedLength];
            Buffer.BlockCopy(decodedData, 0, decodedData2, 0, decodedLength);

            //if (_writer.Position > 1000000 && _writer.CanWrite)
            //{
            //    _writer.Close();
            //}
            //else
            //{
            //    _writer.Write(decodedData, 0, decodedLength);
            //}
            SecondarySoundBuffer secondaryBuffer;
            if (bufferSel == 0)
            {
                secondaryBuffer = _secondaryBuffer;
                bufferSel = 1;
            }
            else
            {
                secondaryBuffer = _secondaryBuffer2;
                bufferSel = 0;
            }

            //secondaryBuffer.Stop();
            //secondaryBuffer.Write<byte>(decodedData2, 0, decodedData2.Length, 0, LockFlags.None);
            //secondaryBuffer.CurrentPosition = 0;
            //secondaryBuffer.Play(0, PlayFlags.None);
            
            _playBuffer.AddSamples(decodedData2, 0, decodedData2.Length);

            //lock (_secondaryBuffer)
            //{
            //    int playCursor, writeCursor;
            //    _secondaryBuffer.GetCurrentPosition(out playCursor, out writeCursor);
            //    int currentWriteSection = playCursor / (_bufferSize / 8);
            //    currentWriteSection = currentWriteSection >= 6 ? currentWriteSection - 6 : currentWriteSection + 2;

            //    int bufferOffset = currentWriteSection * (_bufferSize / 8);
            //    _secondaryBuffer.Write(decodedData, 0, decodedLength, bufferOffset, LockFlags.None);

            //}
        }
    }
}
